home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
276_01
/
a16eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-10-01
|
10KB
|
420 lines
/*
HEADER: CUG276;
TITLE: PIC1650 Cross-Assembler (Portable);
FILENAME: A16EVAL.C;
VERSION: 0.0;
DATE: 06/15/1989;
SEE-ALSO: A16.H;
AUTHORS: William C. Colley III;
*/
/*
PIC1650 Cross-Assembler in Portable C
Copyright (c) 1985,1987,1989 William C. Colley, III
Revision History:
Ver Date Description
0.0 JUNE 1989 Derived from version 0.2 of my portable 8085 cross-
assembler. WCC3.
This file contains the assembler's expression evaluator and lexical analyzer.
The lexical analyzer chops the input character stream up into discrete tokens
that are processed by the expression analyzer and the line assembler. The
expression analyzer processes the token stream into unsigned results of
arithmetic expressions.
*/
/* Get global goodies: */
#include "a16.h"
/* Get access to global mailboxes defined in A16.C: */
extern char line[];
extern int filesp, forwd, pass;
extern unsigned pc;
extern FILE *filestk[], *source;
extern TOKEN token;
/* Expression analysis routine. The token stream from the lexical */
/* analyzer is processed as an arithmetic expression and reduced to an */
/* unsigned value. If an error occurs during the evaluation, the */
/* global flag forwd is set to indicate to the line assembler that it */
/* should not base certain decisions on the result of the evaluation. */
static int bad;
unsigned expr()
{
SCRATCH unsigned u;
unsigned eval();
bad = FALSE;
u = eval(START);
return bad ? 0 : u;
}
static unsigned eval(pre)
unsigned pre;
{
register unsigned op, u, v;
TOKEN *lex();
void exp_error(), unlex();
for (;;) {
u = op = lex() -> valu;
switch (token.attr & TYPE) {
case SEP:
case EOL: unlex(); exp_error('E'); return;
case OPR: if (!(token.attr & UNARY)) { exp_error('E'); break; }
u = eval((op == '+' || op == '-') ?
(unsigned) UOP1 : token.attr & PREC);
switch (op) {
case '-': u = word(-u); break;
case NOT: u ^= 0xffff; break;
case HIGH: u = high(u); break;
case LOW: u = low(u); break;
}
case VAL:
case STR: for (;;) {
op = lex() -> valu;
switch (token.attr & TYPE) {
case SEP:
case EOL: if (pre == LPREN) exp_error('(');
unlex(); return u;
case STR:
case VAL: exp_error('E'); break;
case OPR: if (!(token.attr & BINARY)) {
exp_error('E'); break;
}
if ((token.attr & PREC) >= pre) {
unlex(); return u;
}
if (op != ')')
v = eval(token.attr & PREC);
switch (op) {
case '+': u += v; break;
case '-': u -= v; break;
case '*': u *= v; break;
case '/': u /= v; break;
case MOD: u %= v; break;
case AND: u &= v; break;
case OR: u |= v; break;
case XOR: u ^= v; break;
case '<': u = u < v; break;
case LE: u = u <= v; break;
case '=': u = u == v; break;
case GE: u = u >= v; break;
case '>': u = u > v; break;
case NE: u = u != v; break;
case SHL: if (v > 15)
exp_error('E');
else u <<= v;
break;
case SHR: if (v > 15)
exp_error('E');
else u >>= v;
break;
case ')': if (pre == LPREN)
return u;
exp_error('(');
break;
}
clamp(u);
break;
}
}
break;
}
}
}
static void exp_error(c)
char c;
{
forwd = bad = TRUE; error(c);
}
/* Lexical analyzer. The source input character stream is chopped up */
/* into its component parts and the pieces are evaluated. Symbols are */
/* looked up, operators are looked up, etc. Everything gets reduced */
/* to an attribute word, a numeric value, and (possibly) a string */
/* value. */
static int eol;
static int oldt = FALSE;
static char *lptr;
TOKEN *lex()
{
SCRATCH char c, d, *p;
SCRATCH unsigned b;
SCRATCH OPCODE *o;
SCRATCH SYMBOL *s;
OPCODE *find_operator();
SYMBOL *find_symbol();
void exp_error(), make_number(), pops(), pushc(), trash();
if (oldt) { oldt = FALSE; return &token; }
trash();
if (isalph(c = popc())) {
pushc(c); pops(token.sval);
if (!strcmp(token.sval,"$")) {
token.attr = VAL;
token.valu = pc;
}
else if (o = find_operator(token.sval)) {
token.attr = o -> attr;
token.valu = o -> valu;
}
else {
token.attr = VAL; token.valu = 0;
if (s = find_symbol(token.sval)) {
token.valu = s -> valu;
if (pass == 2 && s -> attr & FORWD) forwd = TRUE;
}
else exp_error('U');
}
}
else if (isnum(c)) {
pushc(c); pops(token.sval);
for (p = token.sval; *p; ++p);
switch (toupper(*--p)) {
case 'B': b = 2; break;
case 'O':
case 'Q': b = 8; break;
default: ++p;
case 'D': b = 10; break;
case 'H': b = 16; break;
}
*p = '\0'; make_number(b);
}
else switch (c) {
case '(': token.attr = UNARY + LPREN + OPR;
goto opr1;
case ')': token.attr = BINARY + RPREN + OPR;
goto opr1;
case '+': token.attr = BINARY + UNARY + ADDIT + OPR;
goto opr1;
case '-': token.attr = BINARY + UNARY + ADDIT + OPR;
goto opr1;
case '*': token.attr = BINARY + UNARY + MULT + OPR;
goto opr1;
case '/': token.attr = BINARY + MULT + OPR;
opr1: token.valu = c;
break;
case '<': token.valu = c;
if ((c = popc()) == '=') token.valu = LE;
else if (c == '>') token.valu = NE;
else pushc(c);
goto opr2;
case '=': token.valu = c;
if ((c = popc()) == '<') token.valu = LE;
else if (c == '>') token.valu = GE;
else pushc(c);
goto opr2;
case '>': token.valu = c;
if ((c = popc()) == '<') token.valu = NE;
else if (c == '=') token.valu = GE;
else pushc(c);
opr2: token.attr = BINARY + RELAT + OPR;
break;
case '\'':
case '"': token.attr = STR;
for (p = token.sval; ; ++p) {
if ((d = getc(source)) == EOF) d = '\n';
if ((d &= 0177) == '\n') {
ungetc('\n',source); exp_error('"'); break;
}
if ((*p = *lptr++ = d) == c) {
if ((d = getc(source)) == EOF) d = '\n';
if ((d &= 0177) == c) *lptr++ = d;
else { ungetc(d,source); break; }
}
}
*p = '\0';
if ((token.valu = token.sval[0]) && token.sval[1])
token.valu = (token.valu << 8) + token.sval[1];
break;
case ',': token.attr = SEP;
break;
case '\n': token.attr = EOL;
break;
}
return &token;
}
static void make_number(base)
unsigned base;
{
SCRATCH char *p;
SCRATCH unsigned d;
void exp_error();
token.attr = VAL;
token.valu = 0;
for (p = token.sval; *p; ++p) {
d = toupper(*p) - (isnum(*p) ? '0' : 'A' - 10);
token.valu = token.valu * base + d;
if (!ishex(*p) || d >= base) { exp_error('D'); break; }
}
clamp(token.valu);
return;
}
int isalph(c)
char c;
{
return (c >= '@' && c <= '~') || (c >= '#' && c <= '&') ||
c == '!' || c == '.' || c == ':' || c == '?';
}
static int isnum(c)
char c;
{
return c >= '0' && c <= '9';
}
static int ishex(c)
char c;
{
return isnum(c) || ((c = toupper(c)) >= 'A' && c <= 'F');
}
static int isalnum(c)
char c;
{
return isalph(c) || isnum(c);
}
/* Push back the current token into the input stream. One level of */
/* pushback is supported. */
void unlex()
{
oldt = TRUE;
return;
}
/* Get an alphanumeric string into the string value part of the */
/* current token. Leading blank space is trashed. */
void pops(s)
char *s;
{
void pushc(), trash();
trash();
for (; isalnum(*s = popc()); ++s);
pushc(*s); *s = '\0';
return;
}
/* Trash blank space and push back the character following